/*********************************************************************
* File: Navigation.h
*
* Defines basic and free navigation as well as collision handling.
*********************************************************************/
#pragma once
#include "../../engine.h"
namespace agents{ class Agent; }

#include "../interfaces/ICollisionManager.h"
#include "../interfaces/INavigation.h"
#include "../interfaces/IFreeNavigation.h"
using namespace agents::interfaces;

/** 
* \brief The agent's maximum rotation speed in degrees per second. 
**/
#define MAXIMUM_MOTION_ROTATION_SPEED 180.0

namespace agents{ namespace modules{
	/**
	* \brief Implements basic and free navigation as well as collision handling.
	* 
	* Defines the agent's basic navigation actuators, automatic navigation to points in 
	* the world, speed control, collision detection and collision handling.
	*
	* \author Instituto Superior Tecnico de Lisboa, Portugal
	* \author Technical University of Lisbon, Portugal
	* 
	* \author Agentes Autonomos e Sistemas Multiagente
	* \author Autonomous Agents and Multiagent Systems
	* 
	* \version	1.0
	* \date		2006/2007
	**/
	class Navigation: public INavigation, public IFreeNavigation, 
		public ICollisionManager {
	public:
		//=====================================================================
		// Enumerations
		//=====================================================================
		/** 
		* \brief Ladder movement directions. 
		**/
		enum LadderMovementDirections
		{
			none,
			up,
			down
		};

		/** 
		* \brief Collision states.
		**/
		class CollisionStates{
		public:
			enum Enumeration
			{
				notDecided,
				probing,
				noMove,
				jump,
				duck,
				jumpAndDuck,
				strafeLeft,
				strafeRight,
			};
		};

		/** 
		* \brief Collision handling probing states.
		**/
		class CollisionProbingStates{
		public:
			enum Enumeration
			{	
				/** Probe jump when colliding **/
				jump = (1 << 0),
				/** Probe duck when colliding **/
				duck = (1 << 1),
				/** Probe strafing when colliding **/
				strafe = (1 << 2)
			};
		};

		//=====================================================================
		// Methods
		//=====================================================================
		Navigation(Agent &owner);
		~Navigation();

		Vector getPosition();
		Vector getAngles();
		void setAngles(Vector angles);

		void moveForward();
		void moveBackwards();
		void moveLeft();
		void moveRight();
		void rotateLeft();
		void rotateRight();
		void rotateUp();
		void rotateDown();
		void jump();
		void duck();

		void setFrontSpeed(float frontSpeed);
		float getFrontSpeed();
		void setSideSpeed(float sideSpeed);
		float getSideSpeed();
		void setRotationSpeed(float rotationSpeed);
		float getRotationSpeed();
		float getEffectiveFrontSpeed();
		float getEffectiveSideSpeed();
		
		// Update 1: Jump/Duck sensors : Start
		bool isJumping();
		bool isDucking();
		// Update 1: End

		void moveToDestination(Vector position);
		Vector getDestination(){ return _destination; }
		bool reachedDestination();
		virtual void stop();

		virtual void newRound();
		virtual void startCycle();
		virtual void endCycle();

		/**
		* \brief Sets the collision handler.
		*
		* By default, it is set to 'this'.
		* 
		* \see agents::interfaces::ICollisionManager::setCollisionHandler
		**/
		void setCollisionHandler(ICollisionHandler* handler){ _collisionHandler = handler; }
		virtual bool detectCollision();
		virtual void handleCollision();
		// Bug 05 - Reset collision state - Start
		void resetCollisionState();
		// Bug 05 - End
		/**
		* \brief Whether the agent is stuck.
		*
		* The agent is considered to be stuck if, while trying to reach a 
		* destination, it doesn't move more than 50 units for more than 5 
		* seconds.
		* 
		* \see agents::interfaces::ICollisionManager::setCollisionHandler
		**/
		virtual bool isStuck(){ return _isStuck; }
		
		/** 
		* \brief Sets the ladder movement direction. 
		* 
		* When in a ladder, setting the destination is not sufficient, as 
		* the movement direction in the ladder must also be set accordingly.
		**/
		void setLadderMovementDirection(LadderMovementDirections ladderMovementDirection)
		{ 
			_ladderMovementDirection = ladderMovementDirection; 
		}
		/** 
		* \brief Gets the ladder movement direction. 
		**/
		LadderMovementDirections getLadderMovementDirection(){ return _ladderMovementDirection; }

	protected:
		/** 
		* \brief The agent.
		**/
		Agent &_owner;
		/** 
		* \brief The distance at which the agent is considered to be close enough to the target. 
		**/
		float _cutoffDistance;

	private:
		void handleLadderNavigation();
		void handleWaterNavigation();
		bool pointIsReachable( Vector point );

		/** 
		* \brief The front speed. 
		* 
		* The agent speed in the forward/backwards direction.
		**/
		float _frontSpeed;
		/** 
		* \brief A factor to ramp the speed when close to the target. 
		**/
		float _rampFrontSpeed;
		/** 
		* \brief The side speed. 
		* 
		* The agent speed in the sideways direction.
		**/
		float _sideSpeed;
		/** 
		* \brief The rotation speed. 
		* 
		* The agent rotation speed.
		**/
		float _rotationSpeed;
		/** 
		* \brief The agent's moving angles. 
		* 
		* The agent moving angles refer to the direction of motion, not to 
		* aiming direction. 
		**/
		Vector _moveAngles;
		/** 
		* \brief The destination position. 
		* 
		* Setting this variable will cause the agent to move towards this position. 
		* However, the agent will only reach it if the position is reachable 
		* and the path is collision-free.
		**/
		Vector _destination;

		/** 
		* \brief Ladder movement direction. 
		* 
		* When in a ladder, setting the destination is not sufficient, as 
		* the movement direction in the ladder must also be set accordingly.
		**/
		LadderMovementDirections _ladderMovementDirection;

		/** 
		* \brief Time previously checked movement speed.
		**/
		float _nextCollisionDetectionTime;
		/**
		* \brief Speed some frames before.
		**/
		float _absPreviousSpeed;
		/** 
		* \brief The position some frames ago.
		**/
		Vector _previousPosition;
		/** 
		* \brief Time of probing different moves.
		**/
		float _collisionProbeTime;
		/** 
		* \brief Time until next collision check.
		**/
		float _noCollisionDetectionTimeInterval;
		/** 
		* \brief The collision handling state.
		**/
		CollisionStates::Enumeration _collisionState;
		/** 
		* \brief Weighted collision resolution movements. 
		**/
		char _collisionMoves[5];
		/** 
		* \brief Index into array of weighted collision resolution movements. 
		**/
		char _collisionStateIndex;
		/** 
		* \brief The current collision handler. 
		* 
		* By default, it is initialized to 'this'.
		**/
		ICollisionHandler* _collisionHandler;

		/** 
		* \brief Whether the agent is stuck. 
		**/
		bool _isStuck;
		/** 
		* \brief The time the collision first occured. 
		*
		* This value is not affected by collision handling behavior, 
		* which might cause the agent to momentarily cease to be colliding
		**/
		double _collisionStartTime;
		/** 
		* \brief Whether the agent is colliding or trying to handle the collision. 
		**/
		bool _isColliding;
		/** 
		* \brief The position when the collision first occured. 
		**/
		Vector _collisionPosition;
	};
}}
